package com.asen.commons.utils;

import com.asen.commons.core.base.domain.Core;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 常用代码缩写工具类--ShortUtil
 *
 * @author menggangaaa
 * @date 2021/3/11
 **/
public class SUtil {

    public static final long F_LONG = -99999L;

    /**
     * 收集去重集合中的id
     */
    public static <T extends Core> List<Long> getIds(Collection<T> list) {
        return getIds(list, Core::getId);
    }

    /**
     * 收集去重集合中的id
     */
    public static <T> List<Long> getIds(Collection<T> list, Function<? super T, Long> mapper) {
        return getIds(list, mapper, null);
    }

    /**
     * 收集去重集合中的id
     */
    public static <T> List<Long> getIds(Collection<T> list, Function<? super T, Long> mapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().map(mapper).filter(IdUtils::isNotEmpty).distinct().collect(Collectors.toList());
        }
        return list.stream().filter(predicate).map(mapper).filter(IdUtils::isNotEmpty).distinct().collect(Collectors.toList());
    }

    /**
     * 收集去重集合中的id
     */
    public static <T extends Core> List<Long> getIdsF(Collection<T> list, Predicate<Long> predicate) {
        return getIdsF(list, Core::getId, predicate);
    }

    /**
     * 收集去重集合中的id
     */
    public static <T> List<Long> getIdsF(Collection<T> list, Function<? super T, Long> mapper, Predicate<Long> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().map(mapper).filter(IdUtils::isNotEmpty).distinct().collect(Collectors.toList());
        }
        return list.stream().map(mapper).filter(IdUtils::isNotEmpty).filter(predicate).distinct().collect(Collectors.toList());
    }

    /**
     * 收集集合中的元素
     */
    public static <T, V> List<V> getList(Collection<T> list, Function<? super T, V> mapper) {
        return getList(list, mapper, null);
    }

    /**
     * 收集集合中的元素
     */
    public static <T> List<T> getListF(Collection<T> list, Predicate<? super T> predicate) {
        return getList(list, Function.identity(), predicate);
    }

    /**
     * 收集集合中的元素
     */
    public static <T, V> List<V> getList(Collection<T> list, Function<? super T, V> mapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().map(mapper).collect(Collectors.toList());
        }
        return list.stream().filter(predicate).map(mapper).collect(Collectors.toList());
    }

    /**
     * 收集集合为map
     */
    public static <T extends Core> Map<Long, T> getMap(Collection<T> list) {
        return getMap(list, Core::getId, Function.identity());
    }

    /**
     * 收集集合为map
     */
    public static <T extends Core> Map<Long, T> getMapF(Collection<T> list, Predicate<? super T> predicate) {
        return getMap(list, Core::getId, Function.identity(), predicate);
    }

    /**
     * 收集集合为map
     */
    public static <T, K> Map<K, T> getMap(Collection<T> list, Function<? super T, K> keyMapper) {
        return getMap(list, keyMapper, Function.identity());
    }

    /**
     * 收集集合为map
     */
    public static <T, K, V> Map<K, V> getMap(Collection<T> list, Function<? super T, K> keyMapper, Function<? super T, V> valueMapper) {
        return getMap(list, keyMapper, valueMapper, null);
    }

    /**
     * 收集集合为map
     */
    public static <T, K, V> Map<K, V> getMap(Collection<T> list, Function<? super T, K> keyMapper, Function<? super T, V> valueMapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || keyMapper == null || valueMapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().collect(Collectors.toMap(keyMapper, valueMapper, ObjectUtil.any()));
        }
        return list.stream().filter(predicate).collect(Collectors.toMap(keyMapper, valueMapper, ObjectUtil.any()));
    }

    /**
     * 收集集合为数值map
     */
    public static <T, K> Map<K, BigDecimal> getDecimalMap(Collection<T> list, Function<? super T, K> keyMapper, Function<? super T, BigDecimal> valueMapper) {
        return getDecimalMap(list, keyMapper, valueMapper, null);
    }

    /**
     * 收集集合为数值map
     */
    public static <T, K> Map<K, BigDecimal> getDecimalMap(Collection<T> list, Function<? super T, K> keyMapper, Function<? super T, BigDecimal> valueMapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || keyMapper == null || valueMapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().collect(Collectors.toMap(keyMapper, item -> DecimalUtils.sure(valueMapper.apply(item)), DecimalUtils::add));
        }
        return list.stream().filter(predicate).collect(Collectors.toMap(keyMapper, item -> DecimalUtils.sure(valueMapper.apply(item)), DecimalUtils::add));
    }

    /**
     * 收集去重集合中的文本值(去除空)
     */
    public static <T> List<String> getStr(Collection<T> list, Function<? super T, String> mapper) {
        return getStr(list, mapper, null);
    }

    /**
     * 收集去重集合中的文本值(去除空)
     */
    public static <T> List<String> getStr(Collection<T> list, Function<? super T, String> mapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().map(mapper).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        }
        return list.stream().filter(predicate).map(mapper).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
    }

    /**
     * 收集去重集合中的文本值(去除空)
     */
    public static <T> Set<String> getStrSet(Collection<T> list, Function<? super T, String> mapper) {
        return getStrSet(list, mapper, null);
    }

    /**
     * 收集去重集合中的文本值(去除空)
     */
    public static <T> Set<String> getStrSet(Collection<T> list, Function<? super T, String> mapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().map(mapper).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        }
        return list.stream().filter(predicate).map(mapper).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
    }

    /**
     * 收集去重集合中的文本值(null->"")
     */
    public static <T> List<String> getStrAll(Collection<T> list, Function<? super T, String> mapper) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return null;
        }
        return list.stream().map(mapper).map(StringUtils::sure).distinct().collect(Collectors.toList());
    }

    /**
     * 收集汇总集合中的数值
     */
    public static <T> BigDecimal getDecimal(Collection<T> list, Function<? super T, BigDecimal> mapper) {
        return getDecimal(list, mapper, null);
    }

    /**
     * 收集汇总集合中的数值,过滤
     */
    public static <T> BigDecimal getDecimal(Collection<T> list, Function<? super T, BigDecimal> mapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return BigDecimal.ZERO;
        }
        if (predicate == null) {
            return list.stream().map(mapper).reduce(BigDecimal.ZERO, DecimalUtils::add);
        }
        return list.stream().filter(predicate).map(mapper).reduce(BigDecimal.ZERO, DecimalUtils::add);
    }

    public static int getInt(Integer integer) {
        return integer == null ? 0 : integer;
    }

    public static <T> long count(Collection<T> list, Function<? super T, ?> mapper) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return 0L;
        }
        return list.stream().map(mapper).distinct().count();
    }

    /**
     * 参数1 != 空 返回参数1 <br/>
     * 参数1 == 空 返回参数2 <br/>
     * 字符串,Long,集合等以值内容判断
     */
    public static <T> T isOr(T obj1, T obj2) {
        if (obj1 instanceof CharSequence) {
            return StringUtils.isNotBlank((CharSequence) obj1) ? obj1 : obj2;
        } else if (obj1 instanceof Long) {
            return IdUtils.isNotEmpty((Long) obj1) ? obj1 : obj2;
        } else if (obj1 instanceof Collection) {
            return CollectionUtils.isNotEmpty((Collection) obj1) ? obj1 : obj2;
        }
        return obj1 != null ? obj1 : obj2;
    }

    public static <T, K> Map<K, List<T>> groupBy(Collection<T> list, Function<? super T, K> mapper) {
        return groupBy(list, mapper, null);
    }

    public static <T, K> Map<K, List<T>> groupBy(Collection<T> list, Function<? super T, K> mapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().collect(Collectors.groupingBy(mapper));
        }
        return list.stream().filter(predicate).collect(Collectors.groupingBy(mapper));
    }

    /**
     * 收集去重集合中的文本值(去除空) 然后使用 拼接符 拼接
     */
    public static <T> String join(Collection<T> list, Function<? super T, String> mapper) {
        return join(list, mapper, ",");
    }

    /**
     * 收集去重集合中的文本值(去除空) 然后使用 拼接符 拼接
     */
    public static <T> String join(Collection<T> list, Function<? super T, String> mapper, String separator) {
        return join(list, mapper, separator, null);
    }

    /**
     * 收集去重集合中的文本值(去除空) 然后使用 拼接符 拼接
     */
    public static <T> String join(Collection<T> list, Function<? super T, String> mapper, String separator, Predicate<? super T> predicate) {
        return StringUtils.join(getStr(list, mapper, predicate), separator);
    }

    public static <T> void addList(Collection<T> list, Collection<? extends T> addList) {
        if (list == null || addList == null) {
            return;
        }
        list.addAll(addList);
    }

    public static <T> boolean removeAll(Collection<T> list, Collection<T> addList) {
        if (list == null || addList == null) {
            return false;
        }
        return list.removeAll(addList);
    }

    public static <T> boolean remove(Collection<T> list, T val) {
        if (list == null || val == null) {
            return false;
        }
        return list.remove(val);
    }

    /**
     * 排序,正序
     */
    public static <T> void asc(List<T> list, Function<? super T, BigDecimal> mapper) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return;
        }
        list.sort((v1, v2) -> DecimalUtils.compareTo(mapper.apply(v1), mapper.apply(v2)));
    }

    /**
     * 排序,倒序
     */
    public static <T> void desc(List<T> list, Function<? super T, BigDecimal> mapper) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return;
        }
        list.sort((v1, v2) -> DecimalUtils.compareTo(mapper.apply(v2), mapper.apply(v1)));
    }

    /**
     * 任意值为false
     */
    public static boolean anyFalse(boolean... values) {
        if (values.length == 0) {
            return false;
        }
        for (boolean bool : values) {
            if (!bool) {
                return true;
            }
        }
        return false;
    }

    public static List<Long> getIds(String idsStr) {
        return getIds(idsStr, ",");
    }

    public static List<Long> getIds(String idsStr, String separator) {
        if (StringUtils.isBlank(idsStr)) {
            return null;
        }
        List<Long> ids = new ArrayList<>();
        String[] split = idsStr.split(separator);
        for (int i = 0; i < split.length; i++) {
            ids.add(Long.valueOf(split[i]));
        }
        return ids;
    }

    /**
     * 实体中金额字段转大写,自动保留两位小数,四舍五入
     */
    public static <T> void decimalToCN(T model, Function<? super T, BigDecimal> getFunc, BiConsumer<? super T, String> setFunc) {
        if (model == null || getFunc == null || setFunc == null) {
            return;
        }
        BigDecimal decimal = getFunc.apply(model);
        String decimalStr = MoneyUtil.number2CN(decimal);
        setFunc.accept(model, decimalStr);
    }

    public static <K, V> V get(Map<K, V> map, K key) {
        if (MapUtils.isEmpty(map) || key == null) {
            return null;
        }
        return map.get(key);
    }

    /**
     * 数组类型转换
     */
    public static <T, E> List<E> convertList(List<T> list, Class<E> clazz) throws Exception {
        return convertList(list, clazz, null);
    }

    /**
     * 数组类型转换
     */
    public static <T, E> List<E> convertList(List<T> list, Class<E> clazz, BiConsumer<? super T, ? super E> action) throws Exception {
        List<E> newList = new ArrayList<>();
        if (CollectionUtils.isEmpty(list)) {
            return newList;
        }
        for (T t : list) {
            E e = clazz.newInstance();
            BeanUtils.copyProperties(t, e);
            if (action != null) {
                action.accept(t, e);
            }
            newList.add(e);
        }
        return newList;
    }

    public static <T> void forEach(List<T> list, Consumer<T> consumer) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        list.forEach(consumer);
    }

    /**
     * 没有id 默认-99999L
     */
    public static List<Long> nullToOne(List<Long> ids) {
        if (ids == null) {
            ids = new ArrayList<>();
        }
        if (ids.size() == 0) {
            ids.add(F_LONG);
        }
        return ids;
    }

    public static <T> void removeIf(List<T> list, Predicate<? super T> filter) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        list.removeIf(filter);
    }

    public static <T> boolean contains(List<T> list, T val) {
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        return list.contains(val);
    }

    public static <K, V> boolean contains(Map<K, V> map, K val) {
        if (CollectionUtils.isEmpty(map) || val == null) {
            return false;
        }
        return map.containsKey(val);
    }

    public static <T, V extends Core> List<V> buildTree(List<T> list, Map<Long, List<T>> map,
                                                        Function<? super T, Integer> sortFunc,
                                                        BiConsumer<? super V, List<V>> childFunc,
                                                        Function<? super T, V> convertFunc) {
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        // 排序
        list.sort(Comparator.comparingInt(item -> SUtil.getInt(sortFunc.apply(item))));
        // 转成vo
        List<V> voList = SUtil.getList(list, convertFunc);
        // 遍历构建
        for (V vo : voList) {
            if (vo == null) {
                continue;
            }
            // 获取子集
            List<T> subList = SUtil.get(map, vo.getId());
            // 递归遍历
            List<V> subVoList = buildTree(subList, map, sortFunc, childFunc, convertFunc);
            // 设置子对象
            childFunc.accept(vo, subVoList);
        }
        return voList;
    }

    public static <T, K> Map<K, Map<K, List<T>>> groupBys(Collection<T> list, Function<? super T, K> mapper1, Function<? super T, K> mapper2) {
        return groupBys(list, mapper1, mapper2, null);
    }

    public static <T, K> Map<K, Map<K, List<T>>> groupBys(Collection<T> list, Function<? super T, K> mapper1, Function<? super T, K> mapper2, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper1 == null || mapper2 == null) {
            return null;
        }
        if (predicate == null) {
            return list.stream().collect(Collectors.groupingBy(mapper1, Collectors.groupingBy(mapper2)));
        }
        return list.stream().filter(predicate).collect(Collectors.groupingBy(mapper1, Collectors.groupingBy(mapper2)));
    }

    public static <T> Integer getInteger(Collection<T> list, Function<? super T, Integer> mapper) {
        return getInteger(list, mapper, null);
    }

    /**
     * 收集汇总集合中的数值,过滤
     */
    public static <T> Integer getInteger(Collection<T> list, Function<? super T, Integer> mapper, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list) || mapper == null) {
            return 0;
        }
        if (predicate == null) {
            return list.stream().map(mapper).mapToInt(t -> t).sum();
        }
        return list.stream().filter(predicate).map(mapper).mapToInt(t -> t).sum();
    }


    /**
     * 分组取最大记录
     * @param list
     * @param Kfunction 分组字段
     * @param Vfunction 比较字段
     * @param predicate 过滤数据
     * @param <T>
     * @param <K>
     * @param <V>
     * @return
     */
    public static <T, K, V> Map<K, T> getMaxMap (List<T> list, Function<T, K> Kfunction, Function<T, V> Vfunction, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }
        if (predicate != null) {
            return list.stream().filter(predicate).collect(Collectors.toMap(Kfunction, a -> a, (t1, t2) -> getObj(t1, t2, Vfunction) >= 0 ? t1 : t2));
        }
        return list.stream().collect(Collectors.toMap(Kfunction, a -> a, (t1, t2) -> getObj(t1, t2, Vfunction) >= 0 ? t1 : t2));
    }
    public static <T, K, V> Map<K, T> getMaxMap (List<T> list, Function<T, K> Kfunction, Function<T, V> Vfunction) {
        return getMaxMap(list, Kfunction, Vfunction, null);
    }

    /**
     * 分组取最小记录
     * @param list
     * @param Kfunction 分组字段
     * @param Vfunction 比较字段
     * @param predicate 过滤数据
     * @param <T>
     * @param <K>
     * @param <V>
     * @return
     */
    public static <T, K, V> Map<K, T> getMinMap (List<T> list, Function<T, K> Kfunction, Function<T, V> Vfunction, Predicate<? super T> predicate) {
        if (CollectionUtils.isEmpty(list)) {
            return new HashMap<>();
        }
        if (predicate != null) {
            return list.stream().filter(predicate).collect(Collectors.toMap(Kfunction, a -> a, (t1, t2) -> getObj(t1, t2, Vfunction) < 0 ? t1 : t2));
        }
        return list.stream().collect(Collectors.toMap(Kfunction, a -> a, (t1, t2) -> getObj(t1, t2, Vfunction) < 0 ? t1 : t2));
    }
    public static <T, K, V> Map<K, T> getMinMap (List<T> list, Function<T, K> Kfunction, Function<T, V> Vfunction) {
        return getMinMap(list, Kfunction, Vfunction, null);
    }

    private static <T, V> int getObj(T t1, T t2, Function<T, V> function) {
        V apply1 = function.apply(t1);
        V apply2 = function.apply(t2);
        if (apply1 == null || apply2 == null) {
            return apply1 != null ? 1 : -1;
        }
        if (apply1 instanceof String) {
            String v1 = (String) apply1;
            String v2 = (String) apply2;
            return v1.compareTo(v2);
        } else if (apply1 instanceof Number) {
            BigDecimal v1 = new BigDecimal(apply1.toString());
            BigDecimal v2 = new BigDecimal(apply2.toString());
            return v1.compareTo(v2);
        }
        return 0;
    }

    /**
     * 分组 不重复拼接
     */
    public static <T, K> Map<K, String> groupDistinctJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction, Predicate<? super T> predicate, String separator) {
        String sep = separator == null ? "," : separator;
        Map<K, String> resultMap = new HashMap<>();
        if (CollectionUtils.isEmpty(list)) {
            return resultMap;
        }
        Map<K, List<String>> map;
        if (predicate != null) {
            map = list.stream().filter(predicate).collect(Collectors.groupingBy(Kfunction, Collectors.mapping(Vfunction, Collectors.toList())));
        } else {
            map = list.stream().collect(Collectors.groupingBy(Kfunction, Collectors.mapping(Vfunction, Collectors.toList())));
        }
        map.forEach((k, v) -> resultMap.put(k, v.stream().distinct().collect(Collectors.joining(sep))));
        return resultMap;
    }
    public static <T, K> Map<K, String> groupDistinctJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction, Predicate<? super T> predicate) {
        return groupDistinctJoin(list, Kfunction, Vfunction, predicate, null);
    }
    public static <T, K> Map<K, String> groupDistinctJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction, String separator) {
        return groupDistinctJoin(list, Kfunction, Vfunction, null, separator);
    }
    public static <T, K> Map<K, String> groupDistinctJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction) {
        return groupDistinctJoin(list, Kfunction, Vfunction, null, null);
    }

    /**
     * 分组拼接
     */
    public static <T, K> Map<K, String> groupJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction, Predicate<? super T> predicate, String separator) {
        String sep = separator == null ? "," : separator;
        Map<K, String> resultMap = new HashMap<>();
        if (CollectionUtils.isEmpty(list)) {
            return resultMap;
        }
        Map<K, List<String>> map;
        if (predicate != null) {
            map = list.stream().filter(predicate).collect(Collectors.groupingBy(Kfunction, Collectors.mapping(Vfunction, Collectors.toList())));
        } else {
            map = list.stream().collect(Collectors.groupingBy(Kfunction, Collectors.mapping(Vfunction, Collectors.toList())));
        }
        map.forEach((k, v) -> resultMap.put(k, String.join(sep, v)));
        return resultMap;
    }
    public static <T, K> Map<K, String> groupJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction, Predicate<? super T> predicate) {
        return groupJoin(list, Kfunction, Vfunction, predicate, null);
    }
    public static <T, K> Map<K, String> groupJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction, String separator) {
        return groupJoin(list, Kfunction, Vfunction, null, separator);
    }
    public static <T, K> Map<K, String> groupJoin(List<T> list, Function<T, K> Kfunction, Function<T, String> Vfunction) {
        return groupJoin(list, Kfunction, Vfunction, null, null);
    }

}
